﻿using System;
using System.ComponentModel;
using System.Windows;
using System.Linq.Expressions;
using System.Windows.Input;
using Microsoft.Practices.Prism.Commands;
using UltimateNavigationFramework.Commands;

namespace Infrastructure.ViewModel
{
    public class ViewModelBase : PropertyChangedNotifier
    {
        #region Navigate
        /// <summary>
        /// Uri Navigation
        /// </summary>
        /// <param name="uri"></param>
        public virtual void Navigate(string uri)
        {
            System.Windows.Browser.HtmlPage.Window.Navigate(new Uri("#" + uri, UriKind.Relative));
        }
        #endregion

        #region Navigate Command
        private ICommand _navigateCommand;
        public ICommand NavigateCommand
        {
            get
            {
                if (_navigateCommand == null)
                {
                    _navigateCommand = new DelegateCommand<NavigationObject>((navigationObject) =>
                    {
                        // This is a fix for empty uri, bug with telerik menu firing command randomly when not clicked.
                        if (!String.IsNullOrEmpty(navigationObject.NavigateUri))
                            this.Navigate(navigationObject.NavigateUri);
                    });
                }
                return _navigateCommand;
            }
        }
        #endregion
    }

    #region Property changed notifier
    public class PropertyChangedNotifier : DependencyObject, INotifyPropertyChanged
    {
        #region Property changed
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion

        #region Notify property changed
        protected virtual void NotifyPropertyChanged<T>(Expression<Func<T>> property)
        {
            NotifyPropertyChanged(property.GetPropertyName());
        }

        protected virtual void NotifyPropertyChanged(string propertyName)
        {
            if (string.IsNullOrEmpty(propertyName)) throw new ArgumentNullException("property");
            if (PropertyChanged != null)
                PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }
        #endregion
    }
    #endregion

    #region Expression extensions
    public static class ExpressionExtensions
    {
        #region Get property name
        public static string GetPropertyName<T>(this Expression<Func<T>> property)
        {
            if (property == null) return null;

            System.Linq.Expressions.MemberExpression expression;
            if (GetMemberExpression(property.Body, out expression))
                return expression.Member.Name;
            else
                return null;
        }
        #endregion

        #region Get member expression
        private static bool GetMemberExpression(System.Linq.Expressions.Expression exp, out MemberExpression memberExp)
        {
            memberExp = exp as MemberExpression;
            if (memberExp != null)
                return true;

            if (IsConversion(exp) && exp is UnaryExpression)
            {
                memberExp = ((UnaryExpression)exp).Operand as MemberExpression;
                if (memberExp != null)
                    return true;
            }
            return false;
        }
        #endregion

        #region Is conversion
        private static bool IsConversion(System.Linq.Expressions.Expression exp)
        {
            return (
                exp.NodeType == ExpressionType.Convert ||
                exp.NodeType == ExpressionType.ConvertChecked
            );
        }
        #endregion
    }
    #endregion
}
